<?php

    /**
     * Significant
     *
     * Compiler for significant url engine
     *
     * @package      Core
     * @subpackage   Url_Engine_Significant
     *
     * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
     */
    class Core_Url_Engine_Significant_Compiler
    {

	////////////////////////////////////////////////////////////////////////////
	//                                 Methods                                //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Compiles the XML file to a PHP cache
         *
         * @param        string      $filename
		 * @throws		 Core_Exception
		 * @throws		 Core_ArgumentException
		 * @throws		 Core_ArgumentNullException
         * @return       void
         */
        public static function compile($filename)
        {
            if ($filename === null) {
				throw new Core_ArgumentNullException('filename is a null reference');
			}

            if (strlen(trim($filename)) == 0) {
				throw new Core_ArgumentException('filename is a zero-length string');
			}

            $parseContent = array();
            $createContent = array();
            $registry = Zend_Registry::getInstance();

            foreach ($registry['modules'] as $currentModule) {
                $file = Core_IO_Path::combine($currentModule, $filename);

                if (!Core_IO_File::exists($file)) {
                    continue;
                }

                if (!($xml = @simplexml_load_file($file))) {
                   throw new Core_Exception('An error occured while parsing XML file: '. $file);
                }

                $typeparam = array(
                                   'string'     => '([^\/]+)',
                                   'char'       => '([^\/])',
                                   'letter'     => '(\w)',
                                   'number'     => '(\d+)',
                                   'int'        => '(\d+)',
                                   'integer'    => '(\d+)',
                                   'digit'      => '(\d)',
                                   'date'       => '([0-2]\d{3}\-(?:0[1-9]|1[0-2])\-(?:[0-2][1-9]|3[0-1]))',
                                   'year'       => '([0-2]\d{3})',
                                   'month'      => '(0[1-9]|1[0-2])',
                                   'day'        => '([0-2][1-9]|[1-2]0|3[0-1])'
                   );

                $createUrlContent = '';
                $createUrlInfos = array();
                $defaultEntrypoints = array();

                foreach ($xml->children() as $name => $tag) {
                    if (!preg_match("/^(.*)entrypoint$/", $name, $m)) {
                        continue;
                    }

                   $requestType = $m[1];
                   $entryPoint = (string)$tag['name'];
                   $generatedentrypoint = $entryPoint;
                   $isHttps = (isset($tag['https']) ? (((string)$tag['https']) == 'true') : false);
                   $isDefault = (isset($tag['default']) ? (((string)$tag['default']) == 'true') : false);

                    if (isset($tag['noentrypoint']) && (string)$tag['noentrypoint'] == 'true') {
                        $generatedentrypoint = '';
                    }

                    $parseInfos = array($isDefault);

                   // if it's the default entry point for the requested type, we set an additionnal
                   // rule that will be used for all urls that don't match the other rules
                    if ($isDefault) {
                        $createUrlInfos['@' . $requestType] = array(2, $entryPoint, $isHttps);
                    }

                    foreach ($tag->url as $url) {
                        $module = (string)$url['module'];

                        if (isset($url['https'])) {
                            $urlhttps =(((string)$url['https']) == 'true');
                        } else {
                            $urlhttps = $isHttps;
                        }

                        if (isset($url['noentrypoint']) && ((string)$url['noentrypoint']) == 'true') {
                            $urlep = '';
                        } else {
                            $urlep = $generatedentrypoint;
                        }

                        // if the entry point isn't the default value of the requested type and if there's only
                        // a module indicated, all the actions for this module will go through this entry point
                        if (!$isDefault && !isset($url['action']) && !isset($url['handler'])) {
                            $parseInfos[] = array($module, '', '/.*/', array(), array(), array(), false);
                            $createUrlInfos[$module . '~*@' . $requestType] = array(3, $urlep, $urlhttps);
                            continue;
                        }

                        $action = (string)$url['action'];

                        if (strpos($action, ':') === false) {
                            $action = 'Index:' . $action;
                        }

                        if (isset($url['actionoverride'])) {
                            $actionOverride = preg_split("/[\s,]+/", (string)$url['actionoverride']);

                            foreach ($actionOverride as &$each) {
                                if (strpos($each, ':') === false) {
                                    $each = 'Index:' . $each;
                                }
                            }
                        } else {
                            $actionOverride = false;
                        }

                        // if there's a handler, parsing and url creation for the module et action must go through this class
                        if (isset($url['handler'])) {
                            $class = (string)$url['handler'];
                            // there must be a name for the module in the selector during the analyze
                            // of the url in the request, because there's no module in the context
                            $p = strpos($class, '~');

                            if ($p === false) {
                                $selclass = $module . '~' . $class;
                            } else if ($p == 0) {
                                $selclass = $module . $class;
                            } else {
                                $selclass = $class;
                            }

                            $selector = new Core_Selector_Url($selclass);
                            if (!isset($url['action'])) {
                                $action = '*';
                            }

                            $createUrlContent .= "include_once('" . $selector->getPath() . "');\n";
                            $parseInfos[] = array($module, $action, $selclass, $actionOverride);
                            $createUrlInfos[$module . '~' . $action . '@' . $requestType] = array(0, $urlep, $urlhttps, $selclass);

                            if ($actionOverride) {
                                foreach ($actionOverride as $ao) {
                                    $createUrlInfos[$module . '~' . $ao . '@' . $requestType] = array(0, $urlep, $urlhttps, $selclass);
                                }
                            }

                            continue;
                        }

                       $escapes = array();
                       $listparam = array();

                        if (isset($url['pathinfo'])) {
                            $path = (string)$url['pathinfo'];
                            $regexppath = $path;

                            if (preg_match_all("/\:([a-zA-Z_]+)/", $path, $m, PREG_PATTERN_ORDER)) {
                                $listparam = $m[1];

                                foreach ($url->param as $var) {
                                    $name = (string)$var['name'];
                                    $k = array_search($name, $listparam);

                                    if ($k === false) {
                                        continue;
                                    }

                                    if (isset($var['escape'])) {
                                        $escapes[$k] = (((string)$var['escape']) == 'true');
                                    } else {
                                        $escapes[$k] = false;
                                    }

                                    if (isset($var['type'])) {
                                        if (isset($typeparam[(string)$var['type']])) {
                                            $regexp = $typeparam[(string)$var['type']];
                                        } else {
                                            $regexp = '([^\/]+)';
                                        }
                                    } else if (isset ($var['regexp'])){
                                        $regexp = '(' . (string)$var['regexp'] . ')';
                                    } else {
                                        $regexp = '([^\/]+)';
                                    }

                                    $regexppath = str_replace(':'. $name, $regexp, $regexppath);
                                }

                                foreach ($listparam as $k => $name) {
                                    if (isset($escapes[$k])) {
                                        continue;
                                    }

                                    $escapes[$k] = false;
                                    $regexppath = str_replace(':'. $name, '([^\/]+)', $regexppath);
                                }
                            }
                        } else {
                            $path = '';
                            $regexppath = '.*';
                        }

                        if (isset($url['optionalTrailingSlash']) && $url['optionalTrailingSlash'] == 'true') {
                            if (substr($regexppath, -1) == '/') {
                                $regexppath .= '?';
                            } else {
                                $regexppath .= '\/?';
                            }
                        }

                        $liststatics = array();

                        foreach ($url->static as $var) {
                            $liststatics[(string)$var['name']] = (string)$var['value'];
                        }

                        $parseInfos[] = array($module, $action, '!^' . $regexppath . '$!', $listparam, $escapes, $liststatics, $actionOverride);
                        $cuisel = $module . '~' . $action . '@' . $requestType;

                        $arr = array(1, $urlep, $urlhttps, $listparam, $escapes,$path, false, $liststatics);
                        if (isset($createUrlInfos[$cuisel])) {
                            if ($createUrlInfos[$cuisel][0] == 4) {
                                $createUrlInfos[$cuisel][] = $arr;
                            } else {
                                $createUrlInfos[$cuisel] = array(4, $createUrlInfos[$cuisel], $arr);
                            }
                        } else {
                            $createUrlInfos[$cuisel] = $arr;
                        }

                        if ($actionOverride) {
                            foreach ($actionOverride as $ao) {
                                $cuisel = $module . '~' . $ao . '@' . $requestType;
                                $arr = array(1, $urlep, $urlhttps, $listparam, $escapes, $path, true, $liststatics);

                                if (isset($createUrlInfos[$cuisel])) {
                                    if ($createUrlInfos[$cuisel][0] == 4) {
                                        $createUrlInfos[$cuisel][] = $arr;
                                    } else {
                                        $createUrlInfos[$cuisel] = array(4, $createUrlInfos[$cuisel], $arr);
                                    }
                                } else {
                                    $createUrlInfos[$cuisel] = $arr;
                                }
                            }
                        }
                    }

                   $parseContent[rawurlencode($entryPoint)] = $parseInfos;
                }

                $createContent = array_merge($createContent, $createUrlInfos);
            }

			$cacheparseurl = Core_IO_Path::combine(PROJECT_TEMP_URLS, '~parse~');
            Core_IO_File::writeAll($cacheparseurl, var_export($parseContent, true));

            $cachecreateurl = Core_IO_Path::combine(PROJECT_TEMP_URLS, '~create~');
            Core_IO_File::writeAll($cachecreateurl, var_export($createContent, true));
        }
    }
